/*
 * @Description: 内联函数 ----- 宏函数的缺陷
 * @Author: stone
 * @Date: 2020-01-31 17:10:49
 * @LastEditTime : 2020-01-31 19:00:01
 * @LastEditors  : stone
 */
#include "test.h"
#include <iostream>
#include <string>
using namespace std;

// #define ADD_MODE(x, y) x + y
#define ADD_MODE(x, y) ((x) + (y)) //这样才可以达到预期的结果

#define CMP_MODE(a, b) ((a) < (b)) ? (a) \
                                   : (b)
/**
 * @description: 
 * @param : 
 * @return: 
 */
static int cmpModeFunc(int a, int b)
{
    return a < b ? a : b;
}
/**
 * @description: 宏函数的优点：以空间换时间，使用普通函数会有入栈出栈的时间开销
 * 宏函数的缺陷：
 *  1、为保证运算的完整性，需加严密的小括号修饰
 *  2、即使加了小括号修饰，有些情况下依然会出现与预期结果不符的情况
 *  3、宏函数不重视作用域
 * 基于上述三个原因，需要采用内联函数来解决一些问题
 * 1、内联函数和普通函数的使用方法相同
 * 2、特殊的地方是：内联函数会在适当的地方像宏函数一样展开，直接跑的是源码，也就是说内联函数即解决了宏函数调用不当而导致
 * 和预期不符结果的问题，又可以在调用的地方作为宏函数一样直接展开源码使用，且具有普通函数的特性，也没有普通函数出栈入栈的开销
 * 3、关键字为：inline
 * @param : 
 * @return: 
 */
// 内联函数使用时需要注意：声明和定义时都必须加inline修饰，否则不会安装内联函数处理
// 成员函数即class的类中定义的函数，都隐藏的加了内联函数inline修饰关键字
// 内联函数和编译器的关系:
// 这个关键字这么好用，为什么很少见有使用：
// 以下情况编译器可能不会考虑将所修饰函数作为内敛函数使用，即使使用了inline关键字修饰，编译器也可能不会采用：
// 1、不能存在任何形式的循环语句，由于系统会认为有循环体的语句过于庞大
// 2、不能存在过多的条件判断语句，过多不是由我们决定，而是根据不同的编译器来做不同的处理
// 3、函数体不能过于庞大，庞大的判断标准是由编译器来决定
// 4、不能对其进行取址操作，由于内联函数跑的是源码，该函数指针没有入口，展开以后就没有这个定义的函数名了
// 综上结论：
// 内敛函数只是编写时给编译器的一个建议，编译器并不一定会接受，如果编译代码时并没有将函数声明为内联函数，编译器也可能将其做成内联函数
// 一个好的编译器，会将一些比较频繁简小的函数转化成内敛函数，所以是否需要内敛，严格说是编译器干的事，所以我们编写代码的时候基本很少使用
inline int cmpModeInlineFunc(int a, int b)
{
    return a < b ? a : b;
}
void test14()
{
    int a = 10, b = 20;
    // int ret = ADD_MODE(a,b); //这里没问题，可以得到预期的结果
    int ret = ADD_MODE(a, b) * 2; //预期结果是60，但是执行完是50
    cout << "a + b = " << ret << endl;
    // ret = CMP_MODE(a, b);   //这里是没有问题的，可以得到预期的结果10
    ret = CMP_MODE(++a, b); //预期结果应该是11，但是执行的结果是12，由于该宏展开后的表达式为：((++a) < (b)) ? (++a):(b)
    //  上述的情况如何避免？如果使用普通函数的话，不会出现上述的情况
    cout << "ret = " << ret << endl;

    a = 10; //重新初始化a为原始数据，使宏函数和普通函数做对比
    ret = cmpModeFunc(++a, b);
    cout << "ret = " << ret << endl;

    a = 10;
    ret = cmpModeInlineFunc(++a, b);
    cout << "ret = " << ret << endl;
    return;
}
